#ifndef __CORE_INIT_H__
#define __CORE_INIT_H__

/**
 *  core/init.h
 *  vse potrebne pro inicializaci jadra
 */

/* pevne stanovene segmenty, ve kterych jadro pracuje */
#define KERNEL_SEGMENT  ((unsigned int)(0x1000))
#define KERNEL_LSEGMENT ((unsigned long)(0x10000000))
#define SYSADDR         ((char far *)(0x80000000))

extern int main(void);

/* promenne, obsahujici segment, ve kterych maji funkce pracovat */
unsigned int  _actual_segment  = KERNEL_SEGMENT;
unsigned long _actual_lsegment = KERNEL_LSEGMENT;

#include <debug.h>

#include <drivers/keyboard.h>
#include <drivers/video.h>
#include <drivers/floppy.h>

#include <core/filesys/fat12.h>
#include <core/exec.h>
#include <core/api.h>

#include <core/io/getchar.h>
#include <core/io/putchar.h>
#include <core/io/clrscr.h>

#include <core/memory/alloc.h>
#include <core/memory/string.h>

#include <kprintf.h>

/******************************************************************************/
/******************************** I N I T *************************************/
/******************************************************************************/

#define RESULT_OK       (0)
#define RESULT_ERROR    (1)
#define RESULT_WARNING  (2)

/**
 *  init_result()
 *  vytiskne na vystup vysledek provedene operace
 *  0 - OK
 *  1 - Error
 *  2 - Warning
 *  jine - Unknown
 */
void init_result(const int result) {
  switch(result) {
    /* [  OK  ] */
    case RESULT_OK:
      textcolor(LIGHTGRAY);
      strput("[");
      textcolor(LIGHTGREEN);
      strput("  OK  ");
      textcolor(LIGHTGRAY);
      strput("]\n");
    break;

    /* [ WARN ] */
    case RESULT_WARNING:
      textcolor(LIGHTGRAY);
      strput("[");
      textcolor(LIGHTRED);
      strput(" WARN ");
      textcolor(LIGHTGRAY);
      strput("]\n");
    break;

    /* [ERROR!] */
    case RESULT_ERROR:
      textcolor(LIGHTGRAY);
      strput("[");
      textcolor(LIGHTRED);
      strput("ERROR!");
      textcolor(LIGHTGRAY);
      strput("]\n");
    break;

    /* [UNKNWN] */
    default:
      textcolor(LIGHTGRAY);
      strput("[");
      textcolor(LIGHTRED);
      strput("UNKNWN");
      textcolor(LIGHTGRAY);
      strput("]\n");
    break;
  }
  return;
}

/**
 *  init()
 *  hlavni funkce pro inicializaci vseho
 */
void init(void) {
  FILE far *conf_file;
  char far *conf_buff;
  char far *conf_actual;
  int i, j;

/*
  vidmode(3);    // clrscr();
  init_alloc();
  init_fat();
  init_dirs();
  init_api();
*/

  /* presuneme se na levy vrchni roh obrazovky a vykreslime ASCII logo */
  vidmode(3);
  gotoxy(1,0);
  kprintf("%59s\n"," _____ _ _       _        _____ _____ ");
  kprintf("%59s\n","|  _  | | |_ ___|_|___   |     |   __|");
  kprintf("%59s\n","|     | |  _| .'| |  _|  |  |  |__   |");
  kprintf("%59s\n","|__|__|_|_| |__,|_|_|    |_____|_____|");

  /* za retezec "Zavadim jadro" doplnime, ze jadro bylo zavedeno uspesne */
  gotoxy(6, 0);
  strput("Zavadim jadro ............................ ");
    init_result(RESULT_OK);

  strput("Inicializace pametoveho modulu ........... ");
    init_alloc();
    init_result(RESULT_OK);

  strput("Inicializace souboroveho systemu FAT ..... ");
    init_fat();
    init_result(RESULT_OK);

  strput("Priprava prace se souborovym systemem .... ");
    init_dirs();
    init_result(RESULT_OK);

  strput("Zjistuji pritomnost APM .................. ");
    init_result(APM_Installed()? RESULT_OK : RESULT_WARNING);

  strput("Zavadim API .............................. ");
    init_api();
    init_result(RESULT_OK);

  /* pokracujeme dale z konfiguracniho souboru.. */
#if 1
  conf_file   = file_open("/etc/init", "r");
  conf_buff   = mem_alloc(file_size(conf_file)+1, KERNEL_SEGMENT);
  conf_actual = mem_alloc(128, KERNEL_SEGMENT);       /* 128 znaku na radek */
  file_read(conf_buff, file_size(conf_file), conf_file);
  /* nyni se bude parsovat konfiguracni soubor */

    for(i=0, j=0; i<=file_size(conf_file); i++) {
      switch(conf_buff[i]) {
        /* mezi [ a ] se nachazi text,
         * ktery popisuje aktualni akci */
        case '[':
          break;
        case ']':
          conf_actual[j] = '\0';
          strput(conf_actual);
          j = 0;
        break;

        /* mezi { a } se nachazi adresa k souboru,
         * ktery se spusti */
        case '{':
          break;
        case '}':
          conf_actual[j] = '\0';
          exec(conf_actual);
          j = 0;
        break;

        /* mezi ( a ) se nachazi stav,
         * ktery se vypise jako prave probehla akce */
        case '(':
          break;
        case ')':
          conf_actual[j] = '\0';

               if(!strcmp(conf_actual, "OK"))
            init_result(RESULT_OK);
          else if(!strcmp(conf_actual, "ERROR"))
            init_result(RESULT_ERROR);
          else if(!strcmp(conf_actual, "WARN"))
            init_result(RESULT_WARNING);
          else init_result(-1);

          j = 0;
        break;

        /* `*' znamena \r\n */
        case '*':
          conf_actual[j++] = '\r';
          conf_actual[j++] = '\n';
        break;

        /* \r a \n se ignoruji */
        case '\r':
        case '\n':
          break;

        /* vse ostatni se doplni do bufferu */
        default:
          conf_actual[j++] = conf_buff[i];
        break;
      }
    }

  /* ----------------------------------------- */
  file_close(conf_file);
  mem_free(conf_buff);
#endif
  asm call _main;

  return;
}

#endif
